//
//  LocationManager.m
//  Eakay
//
//  Created by zach on 2018/11/29.
//  Copyright © 2018年 恒天易开软件科技股份有限公司. All rights reserved.
//

#import "LocationManager.h"

#import <BaiduMapAPI_Base/BMKBaseComponent.h>
#import <BaiduMapAPI_Location/BMKLocationComponent.h>
#import <BaiduMapAPI_Search/BMKSearchComponent.h>

#import <MJExtension/MJExtension.h>
#import "EKApp.h"

NSString * const EKLocationDidUpdatedLocateNotification = @"EKLocationDidUpdatedLocateNotification";
NSString * const EKLocationDidSuccessedLocateNotification = @"EKLocationDidSuccessedLocateNotification";
NSString * const EKLocationDidFailedLocateNotification = @"EKLocationDidFailedLocateNotification";
NSString * const EKLocationDidGeoCodeNotification = @"EKLocationDidGeoCodeNotification";
NSString * const EKLocationDidReverseGeoCodeNotification = @"EKLocationDidReverseGeoCodeNotification";

@interface LocationManager () <BMKGeneralDelegate, BMKLocationServiceDelegate, BMKGeoCodeSearchDelegate> {
    NSString *_appKey;
    BMKMapManager *_mapManager; //百度地图SDK
    BMKLocationService *_locationService; // 定位服务
    BMKGeoCodeSearch *_geoCodeSearch;    // geo检索
}
@property (nonatomic, assign, readwrite) CLLocationCoordinate2D locatedCoordinate;
@property (nonatomic, copy, readwrite) NSString *locatedCityName;
@property (nonatomic, copy, readwrite) NSString *locatedDistrictName;

@property (nonatomic) EKLocationManagerLocationResult locationResult; //定位服务结果
@property (nonatomic) EKLocationManagerLocationServiceStatus locationStatus; // 权限验证状态
@property (nonatomic) BOOL shouldNotifyOtherObjects; //定位成功之后就不需要再通知到外面了，防止外面的数据变化。

@property (nonatomic) BOOL isManualLocate; //非设备真实定位，用户手动变更位置

@end

@implementation LocationManager

+ (instancetype)shared {
    static LocationManager *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [LocationManager new];
    });
    return instance;
}

- (void)dealloc {
    _mapManager = nil;
    // 此处记得不用的时候需要置nil，否则影响内存的释放
    _locationService.delegate = nil;
}

- (instancetype)init {
    self = [super init];
    if (self) {
        self.locationResult = EKLocationManagerLocationResultDefault;
        self.locationStatus = EKLocationManagerLocationServiceStatusDefault;
        
        self.shouldNotifyOtherObjects = YES;
        self.isManualLocate = NO;
    }
    return self;
}

#pragma mark - 百度地图授权
- (BOOL)startMapManagerWithKey:(NSString *)appKey
{
    _mapManager = nil;
    _mapManager = [[BMKMapManager alloc]init];
    // 如果要关注网络及授权验证事件，请设定generalDelegate参数
    BOOL ret = [_mapManager start:appKey  generalDelegate:self];
    _appKey = appKey;
    return ret;
}

#pragma mark - BMKGeneralDelegate
- (void)onGetNetworkState:(int)iError {
    if (0 == iError) {
        NSLog(@"联网成功");
    } else {
        NSLog(@"onGetNetworkState %d",iError);
    }
}
- (void)onGetPermissionState:(int)iError {
    if (0 == iError) {
        NSLog(@"百度地图授权成功");
    } else {
        NSLog(@"onGetPermissionState %d",iError);
    }
}

#pragma mark - 使用定位服务
- (void)startLocation {
    
    self.isManualLocate = NO;
    
    if ([self checkLocationAndShowingAlert:YES]) {
        
        // 获取用户经纬度服务
        _locationService = [[BMKLocationService alloc]init];
        //设置距离过滤器(默认距离是米)
        _locationService.distanceFilter = 15;
        //设置定位精度
        _locationService.desiredAccuracy = kCLLocationAccuracyBest;
        _locationService.delegate =self;
        [_locationService startUserLocationService];
        
        // geo搜索服务
        _geoCodeSearch =[[BMKGeoCodeSearch alloc]init];
        _geoCodeSearch.delegate = self;
        
        self.locationResult = EKLocationManagerLocationResultLocating;
    }
    else {
        [self failedLocationWithResultType:EKLocationDidFailedLocateNotification statusType:self.locationStatus];
    }
}

- (void)stopLocation {
    self.locationResult = EKLocationManagerLocationResultDefault;
    [_locationService stopUserLocationService];
}

- (void)restartLocation {
    [self stopLocation];
    [self startLocation];
}

// 根据坐标获取地址
- (void)geoReverseLocation:(CLLocationCoordinate2D)selectdLocationCoordinate {
    
    self.isManualLocate = YES;
    
    // 根据经纬度查用户当前所在城市
    BMKReverseGeoCodeOption *reverseGeo = [[BMKReverseGeoCodeOption alloc]init];
    reverseGeo.reverseGeoPoint = selectdLocationCoordinate;
    [_geoCodeSearch reverseGeoCode:reverseGeo];
}

// 根据地址获取坐标
- (void)geoCityName:(NSString *)selectedCityName {
    
    self.isManualLocate = YES;
    
    if (selectedCityName) {
        BMKGeoCodeSearchOption *geoCodeSearchOption = [[BMKGeoCodeSearchOption alloc]init];
        geoCodeSearchOption.city= selectedCityName;
        geoCodeSearchOption.address = selectedCityName;
        [_geoCodeSearch geoCode:geoCodeSearchOption];
    }
}

#pragma mark - BMKLocationServiceDelegate - 定位处理

/**
 *用户方向更新后，会调用此函数
 *@param userLocation 新的用户位置
 */
//- (void)didUpdateUserHeading:(BMKUserLocation *)userLocation;

/**
 *用户位置更新后，会调用此函数
 *@param userLocation 新的用户位置
 */
- (void)didUpdateBMKUserLocation:(BMKUserLocation *)userLocation {

    // 根据经纬度查用户当前所在城市
    BMKReverseGeoCodeOption *reverseGeo = [[BMKReverseGeoCodeOption alloc]init];
    reverseGeo.reverseGeoPoint = userLocation.location.coordinate;
    BOOL flag = [_geoCodeSearch reverseGeoCode:reverseGeo];
    if(flag){
        MyLog(@"反geo检索发送成功");
        // 发送成功的话 停止继续获取用户所在的 经纬度
        [self stopLocation];
    }else{
        MyLog(@"反geo检索发送失败");
    }
    
    self.locatedCoordinate = userLocation.location.coordinate;
    
    [[NSNotificationCenter defaultCenter] postNotificationName:EKLocationDidUpdatedLocateNotification object:self userInfo:userLocation.mj_keyValues];

    DDLogVerbose(@"当前坐标===>%@",[NSString stringWithFormat:@"lng:%f, lat:%f", self.locatedCoordinate.longitude, self.locatedCoordinate.latitude]);
}

/**
 *定位失败后，会调用此函数
 *@param error 错误号
 */
- (void)didFailToLocateUserWithError:(NSError *)error {
    
    //之前如果有定位成功的话，以后的定位失败就都不通知到外面了
    if (!self.shouldNotifyOtherObjects) {
        return;
    }
    
    //如果用户还没选择是否允许定位，则不认为是定位失败
    if (self.locationStatus == EKLocationManagerLocationServiceStatusNotDetermined) {
        return;
    }
    
    //如果正在定位中，那么也不会通知到外面
    if (self.locationResult == EKLocationManagerLocationResultLocating) {
        return;
    }
    
    [[NSNotificationCenter defaultCenter] postNotificationName:EKLocationDidFailedLocateNotification object:nil userInfo:error];

    MyLog(@"%@",error);
}


#pragma mark - geo坐标检索

// 反geo搜索回调(根据经纬度查询用户所在城市)
- (void)onGetReverseGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKReverseGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error
{
    // 启动之后的定位解析
    if (error == BMK_SEARCH_NO_ERROR)
    {
        if (!self.isManualLocate) {
            self.locatedCityName = result.addressDetail.city;
            self.locatedDistrictName = result.addressDetail.district;
            
            MyLog(@"我在-----%@",result.addressDetail.city);
            MyLog(@"我在县区名称-----%@",result.addressDetail.district);
            
            self.locationResult = EKLocationManagerLocationResultSuccess;
            self.shouldNotifyOtherObjects = NO;

            [[NSNotificationCenter defaultCenter] postNotificationName:EKLocationDidSuccessedLocateNotification object:self userInfo:result.mj_keyValues];
        }
        else {
            [[NSNotificationCenter defaultCenter] postNotificationName:EKLocationDidReverseGeoCodeNotification object:self userInfo:result.mj_keyValues];
        }
    }else if(error == BMK_SEARCH_PERMISSION_UNFINISHED){
        [self startMapManagerWithKey:_appKey];
    }
}


#pragma mark - geo根据地址检索坐标

// geo搜索回调(根据城市名查询用户经纬度)
- (void)onGetGeoCodeResult:(BMKGeoCodeSearch *)searcher result:(BMKGeoCodeResult *)result errorCode:(BMKSearchErrorCode)error {
    
    if (error == BMK_SEARCH_NO_ERROR) {
        
        if (self.isManualLocate) {            
            [[NSNotificationCenter defaultCenter] postNotificationName:EKLocationDidGeoCodeNotification object:self userInfo:result.mj_keyValues];
        }
    }
    else if(error == BMK_SEARCH_PERMISSION_UNFINISHED){
        [self startMapManagerWithKey:_appKey];
    }
}

#pragma mark -  通知开启权限弹窗delegate

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if (buttonIndex != alertView.cancelButtonIndex) {
        if ([[[UIDevice currentDevice] systemVersion] doubleValue] >= 8.0) {
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]];
        }
        else {
            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"app-settings:"]];
        }
    }
}


#pragma mark - Privates

- (void)failedLocationWithResultType:(EKLocationManagerLocationResult)result statusType:(EKLocationManagerLocationServiceStatus)status
{
    self.locationResult = result;
    self.locationStatus = status;
    [self didFailToLocateUserWithError:nil];
}

- (BOOL)checkLocationAndShowingAlert:(BOOL)showingAlert;
{
    BOOL result = NO;
    BOOL serviceEnable = [self locationServiceEnabled];
    EKLocationManagerLocationServiceStatus authorizationStatus = [self locationServiceStatus];
    
    if (authorizationStatus == EKLocationManagerLocationServiceStatusOK && serviceEnable) {
        result = YES;
    }else if (authorizationStatus == EKLocationManagerLocationServiceStatusNotDetermined) {
        result = YES;
    }else{
        result = NO;
    }
    
    if (serviceEnable && result) {
        result = YES;
    }else{
        result = NO;
    }
    
    if (result == NO) {
        [self failedLocationWithResultType:EKLocationManagerLocationResultFail statusType:self.locationStatus];
    }
    
    if (showingAlert && result == NO) {
        NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
        NSString *app_Name = [infoDictionary objectForKey:@"CFBundleDisplayName"];
        
        NSString *message = [NSString stringWithFormat:@"您没有开启“定位”权限，请允许“%@”访问您的位置。", app_Name];
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil
                                                        message:message
                                                       delegate:self
                                              cancelButtonTitle:@"取消"
                                              otherButtonTitles:@"设置", nil];
        [alert show];
    }
    return result;
}

- (BOOL)locationServiceEnabled {
    if ([CLLocationManager locationServicesEnabled]) {
        self.locationStatus = EKLocationManagerLocationServiceStatusOK;
        return YES;
    } else {
        self.locationStatus = EKLocationManagerLocationServiceStatusUnknownError;
        return NO;
    }
}


- (EKLocationManagerLocationServiceStatus)locationServiceStatus {
    
     self.locationStatus = EKLocationManagerLocationServiceStatusUnknownError;
     BOOL serviceEnable = [CLLocationManager locationServicesEnabled];
     if (serviceEnable) {
         CLAuthorizationStatus authorizationStatus = [CLLocationManager authorizationStatus];
         switch (authorizationStatus) {
             case kCLAuthorizationStatusNotDetermined:
                 self.locationStatus = EKLocationManagerLocationServiceStatusNotDetermined;
                 break;
     
             case kCLAuthorizationStatusAuthorizedWhenInUse:
             case kCLAuthorizationStatusAuthorizedAlways:
                 self.locationStatus = EKLocationManagerLocationServiceStatusOK;
                 break;
     
             case kCLAuthorizationStatusDenied:
                 self.locationStatus = EKLocationManagerLocationServiceStatusNoAuthorization;
                 break;
     
             default:
                 if (![EKApp shared].isReachable) {
                     self.locationStatus = EKLocationManagerLocationServiceStatusNoNetwork;
                 }
                 break;
         }
     }
     else {
         self.locationStatus = EKLocationManagerLocationServiceStatusUnAvailable;
     }
    
    return self.locationStatus;
}
@end
